View Javadoc

1   /*
2    * TouchGraph Software License
3    *
4    *
5    * Copyright (c) 2001 Alexander Shapiro. All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer. 
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution,
20   *    if any, must include the following acknowledgment:  
21   *       "This product includes software developed by 
22   *        TouchGraph (http://www.touchgraph.com/)."
23   *    Alternately, this acknowledgment may appear in the software itself,
24   *    if and wherever such third-party acknowledgments normally appear.
25   *
26   * 4. The name "TouchGraph" must not be used to endorse or promote 
27   *    products derived from this software without prior written 
28   *    permission.  For written permission, please contact 
29   *    alex@touchgraph.com
30   *
31   * 5. Products derived from this software may not be called "TouchGraph",
32   *    nor may "TouchGraph" appear in their name, without prior written
33   *    permission of TouchGraph.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE 
39   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
40   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
41   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
42   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
43   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
44   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
45   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46   * =====================================================================
47   *
48   */
49  
50  package com.touchgraph.graphlayout.interaction;
51  
52  import java.awt.event.*;
53  
54  import javax.swing.JScrollBar;
55  
56  import com.touchgraph.graphlayout.*;
57  
58  /*** HyperScroll.  Responsible for producing that neat hyperbolic effect.
59    * (Which isn't really hyperbolic, but just non-linear).
60    * Demonstrates the usefulness of Lenses.
61    *
62    * @author   Alexander Shapiro                                        
63    * @version  1.06
64    */
65  public class HyperScroll implements GraphListener {
66  
67      private JScrollBar hyperSB;
68      private TGPanel tgPanel;
69      HyperLens hyperLens;
70      double inverseArray[]=new double[200]; //Helps calculate the inverse of the Hyperbolic function
71      double width; //Initially was intended to change the function of the lens depending on screen size,
72                    //but now functions as a constant.
73  
74      public HyperScroll(TGPanel tgp) {    
75          tgPanel=tgp;
76          hyperSB = new JScrollBar(JScrollBar.HORIZONTAL, 0, 8, 0, 108);
77          hyperSB.addAdjustmentListener(new hyperAdjustmentListener());
78          
79          hyperLens = new HyperLens();
80          width= 2000;//tgPanel.getSize().width/2;
81          updateInverseArray();
82          
83          tgPanel.addGraphListener(this);
84      }
85      
86      public JScrollBar getHyperSB() { return hyperSB; }
87  
88      public HyperLens getLens() { return hyperLens; }
89      
90      public void graphMoved() {} //From GraphListener interface
91      public void graphReset() { hyperSB.setValue(0); } //From GraphListener interface
92      
93      private class hyperAdjustmentListener implements AdjustmentListener {
94          public void adjustmentValueChanged(AdjustmentEvent e) {
95              updateInverseArray();
96              tgPanel.repaintAfterMove();
97          }
98      }
99      
100     double rawHyperDist (double dist) {  //The hyperbolic transform
101         if(hyperSB.getValue()==0) return dist;
102         double hyperV=hyperSB.getValue();
103         return Math.log(dist/(Math.pow(1.5,(70-hyperV)/40)*80) +1);
104         /*
105         double hyperD = Math.sqrt(dist+(10.1-Math.sqrt(hyperV)))-Math.sqrt(10.1-Math.sqrt(hyperV));
106         */
107         
108     }    
109     
110     double hyperDist (double dist) { 
111         
112         double hyperV=hyperSB.getValue();
113         //Points that are 250 away from the center stay fixed.
114         double hyperD= rawHyperDist(dist)/rawHyperDist(250)*250;
115         double fade=hyperV;
116         double fadeAdjust=100;
117         hyperD=hyperD*fade/fadeAdjust+dist*(fadeAdjust-fade)/fadeAdjust;
118         return hyperD;
119 
120     }    
121     
122     void updateInverseArray(){
123         double x;
124         for(int i=0;i<200;i++) { 
125             x=width*i/200; //Points within a radius of 'width' will have exact inverses.
126             inverseArray[i]=hyperDist(x);
127         }    
128     };
129     
130     int findInd(int min, int max, double dist) {
131         int mid=(min+max)/2;
132         if (inverseArray[mid]<dist)
133             if (max-mid==1) return max;
134             else return findInd(mid,max,dist);
135         else
136             if (mid-min==1) return mid;
137             else return findInd(min,mid,dist);
138     }
139     
140     double invHyperDist (double dist) { //The inverse of hyperDist
141         
142         if (dist==0) return 0;
143         int i;
144         if (inverseArray[199]<dist) i=199;
145         else i=findInd(0,199,dist);        
146         double x2=inverseArray[i];
147         double x1=inverseArray[i-1];
148         double j= (dist-x1)/(x2-x1);
149         return(((double) i+j-1)/200.0*width);
150     }
151 
152 
153      class HyperLens extends TGAbstractLens {
154         protected void applyLens(TGPoint2D p) {
155             double dist=Math.sqrt(p.x*p.x+p.y*p.y);
156             if(dist>0) {
157                 p.x=p.x/dist*hyperDist(dist);
158                 p.y=p.y/dist*hyperDist(dist);
159             }
160             else { p.x =0; p.y=0;}
161         }
162         
163         protected void undoLens(TGPoint2D p) {
164             double dist=Math.sqrt(p.x*p.x+p.y*p.y);
165             if(dist>0) {
166                 p.x=p.x/dist*invHyperDist(dist);
167                 p.y=p.y/dist*invHyperDist(dist);
168             }
169             else { p.x =0; p.y=0;}
170         }
171     }
172 
173 //Things can't get much more complex then this, if you don't use an inverse function
174 /*
175      class HyperLens extends TGAbstractLens {
176         protected void applyLens(TGPoint2D p) {
177             if(p.x!=0)
178             p.x=p.x/Math.sqrt(Math.abs(p.x))*Math.sqrt(tgPanel.getSize().width/2);
179             if(p.y!=0)
180             p.y=p.y/Math.sqrt(Math.abs(p.y))*Math.sqrt(tgPanel.getSize().height/2);
181         }
182         
183         protected void undoLens(TGPoint2D p) {
184             
185             p.x=(p.x/Math.sqrt(tgPanel.getSize().width/2));
186             p.x=p.x*Math.abs(p.x);
187             p.y=(p.y/Math.sqrt(tgPanel.getSize().height/2));
188             p.y=p.y*Math.abs(p.y);
189         }
190     }
191  */
192 
193 } // end com.touchgraph.graphlayout.interaction.HyperScroll